/* *
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
/* eslint-disable valid-jsdoc */
var getCentroid = function (simplex) {
  var arr = simplex.slice(0, -1),
    length = arr.length,
    result = [],
    sum = function (data, point) {
      data.sum += point[data.i];
      return data;
    };
  for (var i = 0; i < length; i++) {
    result[i] = arr.reduce(sum, { sum: 0, i: i }).sum / length;
  }
  return result;
};
/**
 * Finds an optimal position for a given point.
 * @todo add unit tests.
 * @todo add constraints to optimize the algorithm.
 * @private
 * @param {Highcharts.NelderMeadTestFunction} fn
 *        The function to test a point.
 * @param {Highcharts.NelderMeadPointArray} initial
 *        The initial point to optimize.
 * @return {Highcharts.NelderMeadPointArray}
 *         Returns the opimized position of a point.
 */
var nelderMead = function nelderMead(fn, initial) {
  var maxIterations = 100,
    sortByFx = function (a, b) {
      return a.fx - b.fx;
    },
    pRef = 1, // Reflection parameter
    pExp = 2, // Expansion parameter
    pCon = -0.5, // Contraction parameter
    pOCon = pCon * pRef, // Outwards contraction parameter
    pShrink = 0.5; // Shrink parameter
  /**
   * @private
   */
  var weightedSum = function weightedSum(weight1, v1, weight2, v2) {
    return v1.map(function (x, i) {
      return weight1 * x + weight2 * v2[i];
    });
  };
  /**
   * @private
   */
  var getSimplex = function getSimplex(initial) {
    var n = initial.length,
      simplex = new Array(n + 1);
    // Initial point to the simplex.
    simplex[0] = initial;
    simplex[0].fx = fn(initial);
    // Create a set of extra points based on the initial.
    for (var i = 0; i < n; ++i) {
      var point = initial.slice();
      point[i] = point[i] ? point[i] * 1.05 : 0.001;
      point.fx = fn(point);
      simplex[i + 1] = point;
    }
    return simplex;
  };
  var updateSimplex = function (simplex, point) {
    point.fx = fn(point);
    simplex[simplex.length - 1] = point;
    return simplex;
  };
  var shrinkSimplex = function (simplex) {
    var best = simplex[0];
    return simplex.map(function (point) {
      var p = weightedSum(1 - pShrink, best, pShrink, point);
      p.fx = fn(p);
      return p;
    });
  };
  var getPoint = function (centroid, worst, a, b) {
    var point = weightedSum(a, centroid, b, worst);
    point.fx = fn(point);
    return point;
  };
  // Create a simplex
  var simplex = getSimplex(initial);
  // Iterate from 0 to max iterations
  for (var i = 0; i < maxIterations; i++) {
    // Sort the simplex
    simplex.sort(sortByFx);
    // Create a centroid from the simplex
    var worst = simplex[simplex.length - 1];
    var centroid = getCentroid(simplex);
    // Calculate the reflected point.
    var reflected = getPoint(centroid, worst, 1 + pRef, -pRef);
    if (reflected.fx < simplex[0].fx) {
      // If reflected point is the best, then possibly expand.
      var expanded = getPoint(centroid, worst, 1 + pExp, -pExp);
      simplex = updateSimplex(
        simplex,
        expanded.fx < reflected.fx ? expanded : reflected
      );
    } else if (reflected.fx >= simplex[simplex.length - 2].fx) {
      // If the reflected point is worse than the second worse, then
      // contract.
      var contracted;
      if (reflected.fx > worst.fx) {
        // If the reflected is worse than the worst point, do a
        // contraction
        contracted = getPoint(centroid, worst, 1 + pCon, -pCon);
        if (contracted.fx < worst.fx) {
          simplex = updateSimplex(simplex, contracted);
        } else {
          simplex = shrinkSimplex(simplex);
        }
      } else {
        // Otherwise do an outwards contraction
        contracted = getPoint(centroid, worst, 1 - pOCon, pOCon);
        if (contracted.fx < reflected.fx) {
          simplex = updateSimplex(simplex, contracted);
        } else {
          simplex = shrinkSimplex(simplex);
        }
      }
    } else {
      simplex = updateSimplex(simplex, reflected);
    }
  }
  return simplex[0];
};
var content = {
  getCentroid: getCentroid,
  nelderMead: nelderMead,
};
export default content;
